package io.mft.commons.config;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.hutool.core.util.ObjectUtil;
import io.mft.commons.exception.MFTException;
/**
 * 配置提供者
 * @说明：TODO
 * @类型名称：ConfigProvider
 * @创建者: 胡常建  
 * @创建时间: 2021年2月18日 下午6:01:40
 * @修改者: 胡常建  
 * @修改时间: 2021年2月18日 下午6:01:40
 */
public class ConfigProvider {

	public enum Env{
		Dev,Test,Prod
	}
	public final static String DEFAULT_CONFIG_NAMESPACE="application";
	static Map<ClassLoader,Map<String, String>> configValues = new ConcurrentHashMap<ClassLoader,Map<String, String>>();
	static Map<ClassLoader, Map<String, Map<String, Object>>> configObjectValues = new ConcurrentHashMap<ClassLoader, Map<String, Map<String, Object>>>();
	static Logger logger=LoggerFactory.getLogger(ConfigProvider.class);
	public static void init() {
	}
	public interface ConfigProvideLoader{
		Map<String, Object> load();
		String namespace();
		ClassLoader classLoader();
	
		default CompletedLoadHandler completedLoadHandler() {
			return new CompletedLoadHandler() {
				
				@Override
				public void handle() {
					// TODO Auto-generated method stub
					
				}
			};
		}
		
	}
	public interface CompletedLoadHandler{
		void handle();
	}
	/**
	static public class ApplicationConfigProvideLoader extends ApplicationCustomizeConfigNamespaceConfigProvideLoader{
		public ApplicationConfigProvideLoader(ClassLoader classLoader) {
			super(classLoader, DEFAULT_CONFIG_NAMESPACE);
		}
		@Override
		public Map<String, Object> load() {
			String path=DEFAULT_CONFIG_NAMESPACE+".yml";
			Map<String, Object> configObjectMap=parseYaml(classLoader, path);
			return configObjectMap;
		}
		@Override
		public CompletedLoadHandler completedLoadHandler() {
			// TODO Auto-generated method stub
			return new CompletedLoadHandler() {
				
				@Override
				public void handle() {
					// TODO Auto-generated method stub
					ApplicationEnvConfigProvideLoader applicationEnvConfigProvideLoader=new ApplicationEnvConfigProvideLoader(classLoader);
					ConfigProvider.loadConfig(applicationEnvConfigProvideLoader);
					
					Map<String, Object> defaultNamespaceConfigObjectMap=getNamespaceConfigObject(classLoader, DEFAULT_CONFIG_NAMESPACE);
					List<String> customizeConfigNamespaces=getMapValue(defaultNamespaceConfigObjectMap, "customizeConfigNamespace");
					if (customizeConfigNamespaces!=null) {
						customizeConfigNamespaces.forEach(customizeConfigNamespace->{
							ApplicationCustomizeConfigNamespaceConfigProvideLoader applicationCustomizeConfigNamespaceConfigProvideLoader=new ApplicationCustomizeConfigNamespaceConfigProvideLoader(classLoader, customizeConfigNamespace);
							ConfigProvider.loadConfig(applicationCustomizeConfigNamespaceConfigProvideLoader);
						});
					}
				}
			};
		}
		
	}
	
	static public class ApplicationCustomizeConfigNamespaceConfigProvideLoader implements ConfigProvideLoader{
		protected ClassLoader classLoader;
		private String customizeConfigNamespace;
		public ApplicationCustomizeConfigNamespaceConfigProvideLoader(ClassLoader classLoader,String customizeConfigNamespace) {
			this.classLoader=classLoader;
			this.customizeConfigNamespace=customizeConfigNamespace;
		}
		@Override
		public Map<String, Object> load() {
			String path=customizeConfigNamespace+".yml";
			Map<String, Object> configObjectMap=parseYaml(classLoader, path);
			return configObjectMap;
		}

		@Override
		public String namespace() {
			return customizeConfigNamespace;
		}

		@Override
		public ClassLoader classLoader() {
			return classLoader;
		}
		@Override
		public CompletedLoadHandler completedLoadHandler() {
			return new CompletedLoadHandler() {
				
				@Override
				public void handle() {
					// TODO Auto-generated method stub
					
				}
			};
		}
		
	}
	
	static public class ApplicationEnvConfigProvideLoader extends ApplicationCustomizeConfigNamespaceConfigProvideLoader{
		public ApplicationEnvConfigProvideLoader(ClassLoader classLoader) {
			super(classLoader, DEFAULT_CONFIG_NAMESPACE);
		}
		@Override
		public Map<String, Object> load() {
			String profilesActiveKey="spring.profiles.active";
			String active=get(classLoader,DEFAULT_CONFIG_NAMESPACE,profilesActiveKey,Env.Prod.name());
			if (ObjectUtil.isNotEmpty(active)) {
				String path=DEFAULT_CONFIG_NAMESPACE+"-"+active+".yml";
				Map<String, Object> configObjectMap=parseYaml(classLoader, path);
				return configObjectMap;
			}else {
				Map<String, Object> kv=new ConcurrentHashMap<String, Object>();
				return kv;
			}
		}
	}
	
	**/

	
	public static void loadConfig(ConfigProvideLoader configProvideLoader) {
		try {
			Map<String, Object> configObject=configProvideLoader.load();
			if (configObject==null||configObject.size()==0) {
				return;
			}
			Map<String, Map<String, Object>> classLoaderKv=configObjectValues.get(configProvideLoader.classLoader());
			if (classLoaderKv==null) {
				classLoaderKv=new ConcurrentHashMap<>();
				configObjectValues.put(configProvideLoader.classLoader(), classLoaderKv);
			}
			Map<String, Object> namespaceKv=classLoaderKv.get(configProvideLoader.namespace());
			if (namespaceKv==null) {
				namespaceKv=new ConcurrentHashMap<String, Object>();
				classLoaderKv.put(configProvideLoader.namespace(), namespaceKv);
			}
			try {
				namespaceKv.putAll(configObject);
			} catch (Exception e) {
				logger.error("",e);
			}
			
			Map<String, String> stringKvMap=mapTostringKv("", classLoaderKv);
			Map<String, String> stringMap=configValues.get(configProvideLoader.classLoader());
			if (stringMap==null) {
				configValues.put(configProvideLoader.classLoader(), stringKvMap);
			}else {
				stringMap.putAll(stringKvMap);
			}
			configProvideLoader.completedLoadHandler().handle();
		} catch (Exception e) {
			logger.error("",e);
		}

	}
	

	public static <T> T getConfigObject(ClassLoader loader,String key) {
		return getConfigObject(loader, DEFAULT_CONFIG_NAMESPACE, key);
	}
	@SuppressWarnings("unchecked")
	public static <T> T getConfigObject(ClassLoader loader,String namespace,String key) {
		Map<String, Object> map= getNamespaceConfigObject(loader, namespace);
		if (map!=null) {
			Object obj=map.get(key);
			T tobj=(T)obj;
			return tobj;
		}else {
			throw new MFTException(-1,"未获取到命名空间["+namespace+"]配置对象");
		}
	}
	public static List<ClassLoader> getConfigClassLoaders() {
		List<ClassLoader> classLoaders=new ArrayList<>(configObjectValues.keySet());
		return classLoaders;
	}
	public static Map<String, Object> getNamespaceConfigObject(ClassLoader loader,String namespace) {
		if (!configObjectValues.containsKey(loader)) {
			throw new MFTException(-1,"未获取到类加载器对应的配置对象");
		}
		Map<String, Object> map= configObjectValues.get(loader).get(namespace);
		return map;
	}
	public static Map<String, Object> getHostProgramNamespaceConfigObject(String namespace) {
		return getNamespaceConfigObject(ConfigProvider.class.getClassLoader(), namespace);
	}
	public static <T> T getHostProgramConfigObject(String key) {
		return getConfigObject(ConfigProvider.class.getClassLoader(), key);
	}
	public static <T> T getHostProgramConfigObject(String namespace,String key) {
		return getConfigObject(ConfigProvider.class.getClassLoader(),namespace, key);
	}
	
	
	public static String getHostProgramConfigValue(String key,String defaultValue) {
		return get(ConfigProvider.class.getClassLoader(), DEFAULT_CONFIG_NAMESPACE, key, defaultValue);
	}
	public static int getHostProgramConfigValue(String key,int defaultValue) {
		String v=getHostProgramConfigValue(key, "");
		if (ObjectUtil.isNotEmpty(v)) {
			return Integer.valueOf(v);
		}else {
			return defaultValue;
		}
	}
	@SuppressWarnings("unchecked")
	public static <T> T getMapValue(Map<?, ?> map,String key) {
		if (map==null) {
			return null;
		}
		Object object=map.get(key);
		if (object!=null) {
			T t=(T)object;
			return t;
		}else {
			return null;
		}
	}
	public static void initApplicationConfig(ClassLoader loader) {
		try {
			if (!configValues.containsKey(loader)) {
				synchronized (configValues) {
					if (!configValues.containsKey(loader)) {
						//ApplicationConfigProvideLoader applicationConfigProvideLoader=new ApplicationConfigProvideLoader(loader);
						//loadConfig(applicationConfigProvideLoader);
						logger.debug("类加载器:{}-加载器hashcode:{}-初始化完成配置容器->>>框架配置容器总数量:{}",loader.getClass().getName(),loader.hashCode(),configValues.size());
					}
				}
			}
		} catch (Exception e) {
			logger.error("",e);
		}
	}
	public static void put(ClassLoader loader,String key,String value) {
		Map<String, String> kv=configValues.get(loader);
		if (kv!=null) {
			kv.put(key, value);
		}
	}
	private static ConcurrentHashMap<String, String>   mapTostringKv(String superkey,Map<?, ?> map) {
		ConcurrentHashMap<String, String> kv=new ConcurrentHashMap<String, String>();
		map.keySet().forEach(key->{
			Object v=map.get(key);
			if (v instanceof Map) {
				String newKey=String.valueOf(key);
				if (ObjectUtil.isNotEmpty(superkey)) {
					 newKey=superkey+"."+key;
				}
				Map<String, String> tmap=mapTostringKv(newKey, (Map<?,?>)v);
				kv.putAll(tmap);
			}else {
				String newKey=String.valueOf(key);
				if (ObjectUtil.isNotEmpty(superkey)) {
					 newKey=superkey+"."+key;
				}
				kv.put(newKey, String.valueOf(v));
			}
		});
		return kv;
	}
	public static Map<String, String> getConfig(ClassLoader loader) {
		if (!configValues.containsKey(loader)) {
			initApplicationConfig(loader);
		}
		return configValues.get(loader);
	}
	public static Map<String, String> getConfig() {
		ClassLoader loader = Thread.currentThread().getContextClassLoader();
		return getConfig(loader);
	}
	public static String get(String key,String defaultValue) {
		ClassLoader loader = Thread.currentThread().getContextClassLoader();
		return get(loader, key, defaultValue);
	}
	public static int get(String key,int defaultValue) {
		String v=get(key, "");
		if (ObjectUtil.isEmpty(v)) {
			return defaultValue;
		}else {
			return Integer.valueOf(v);
		}
	}
	public static int get(ClassLoader loader,String key,int defaultValue) {
		return get(loader, DEFAULT_CONFIG_NAMESPACE, key, defaultValue);
	}
	public static int get(ClassLoader loader,String namespace,String key,int defaultValue) {
		String v=get(loader,namespace,key, "");
		if (ObjectUtil.isEmpty(v)) {
			return defaultValue;
		}else {
			return Integer.valueOf(v);
		}
	}
	public static String get(ClassLoader classLoader,String key,String defaultValue) {
		return get(classLoader, DEFAULT_CONFIG_NAMESPACE, key, defaultValue);
	}
	
	public static String get(ClassLoader classLoader,String namespace,String key,String defaultValue) {
		Map<String, String> configObject = getConfig(classLoader);
		String vk=namespace+"."+key;
		Object v = configObject.get(vk);
		if (ObjectUtil.isEmpty(v)) {
			v=defaultValue;
		}
		logger.debug("类加载器:{}-加载器hashcode:{}-获取配置:{}={}",classLoader.getClass().getName(),classLoader.hashCode(),key,v);
		return String.valueOf(v);
	}
}
